package backend

import (
	"net/http"
	"strconv"

	"lanmon/internal/utils"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
)

func NewAdminController() *AdminController {
	admin := &AdminController{}
	return admin
}

type AdminController struct {
}

type lanClient struct {
	ClientId string `json:"client_id,omitempty"`
	Sysinfo  string `json:"sysinfo,omitempty"`
}

// ListClients godoc
// @Summary      list clients
// @Description	 list all clients online
// @Accept       json
// @Produce      json
// @Router       /api/v1/admin/list [get]
func (admin *AdminController) ListClients(ctx *gin.Context) {
	mqtt := lanBackend.MQTTServer

	var count = 0
	result := make([]*lanClient, 0)

	{
		mqtt.Lock()
		defer mqtt.Unlock()

		clients := mqtt.Clients
		count = len(clients)

		for key, val := range clients {
			info, err := val.info.ToJson()
			if err != nil {
				log.Warn("ListClients: convert to json error. ignore it.", err)
				continue
			}
			result = append(result, &lanClient{
				ClientId: key,
				Sysinfo:  info,
			})
		}
	}

	ctx.JSON(http.StatusOK, utils.NewOkResp(gin.H{
		"count":  count,
		"result": result,
	}))
}

// BroadcastClients godoc
// @Summary      broadcast action
// @Description	 broadcast action to all clients online
// @Param	action	path	int	true	"broadcast action"
// @Accept       json
// @Produce      json
// @Router       /api/v1/admin/broadcast/{action} [post]
func (admin *AdminController) BroadcastClients(ctx *gin.Context) {
	action, err := strconv.Atoi(ctx.Param("action"))
	if err != nil {
		ctx.JSON(http.StatusOK, utils.NewFailResp(utils.E_INVALID_PARAM, utils.MSG_INVALID_PARAM))
		return
	}

	switch MqttAction(action) {
	case BroadcastShutdown:
		var shutdownArgs struct {
			Reboot int `json:"reboot,omitempty"`
		}
		ctx.BindJSON(&shutdownArgs)

		var reboot = false
		if shutdownArgs.Reboot == 1 {
			reboot = true
		}
		lanBackend.MQTTServer.BroadcastShutdown(reboot)

	case BroadcastClientLogin:
		broadcast := newMqttBroadcast(BroadcastClientLogin, nil)
		lanBackend.MQTTServer.publishBroadcast(broadcast)
	}
}

// CommandClients godoc
// @Summary      send command action
// @Description	 send command action to the client online
// @Param	action		path	int		true	"command action"
// @Param	clientId	path	string	true	"client ID"
// @Accept       json
// @Produce      json
// @Router       /api/v1/admin/command/{action}/{clientId} [post]
func (admin *AdminController) CommandClients(ctx *gin.Context) {
	action, err := strconv.Atoi(ctx.Param("action"))
	if err != nil {
		ctx.JSON(http.StatusOK, utils.NewFailResp(utils.E_INVALID_PARAM, utils.MSG_INVALID_PARAM))
		return
	}

	clientId := ctx.Param("clientId")
	if len(clientId) < 1 {
		ctx.JSON(http.StatusOK, utils.NewFailResp(utils.E_INVALID_PARAM, utils.MSG_INVALID_PARAM))
		return
	}
	found := lanBackend.MQTTServer.HasClient(clientId)
	if !found {
		ctx.JSON(http.StatusOK, utils.NewFailResp(utils.E_NOT_FOUND, utils.MSG_NOT_FOUND))
		return
	}

	switch MqttAction(action) {
	case CommandShutdown:
		var shutdownArgs struct {
			Reboot int `json:"reboot,omitempty"`
		}
		ctx.BindJSON(&shutdownArgs)

		var reboot = false
		if shutdownArgs.Reboot == 1 {
			reboot = true
		}
		lanBackend.MQTTServer.CommandShutdown(clientId, reboot)

	case CommandClientLogin:
		command := newMqttCommand(clientId, CommandClientLogin, nil)
		lanBackend.MQTTServer.publishCommand(command)
	}
}
